﻿using ImageManager.DBAccess;
using System.Security.Cryptography;

namespace ImageManager.DBAccess
{
    public class CondCollection
    {
        public static CondCollection True()
        {
            var v = new CondCollection();
            v.conds.Add(new WhereConditional("", OpEnum.AwayTrue, ""));
            return v;
        }
        public void AddWhereCond(WhereConditional cond)
        {
            conds.Add(cond);
        }
        List<WhereConditional> conds = new List<WhereConditional>();
        public List<WhereConditional> ToConds()
        {
            return conds;
        }
        public CondCollection Eq(string key, object? value)
        {
            if (value != null)
                conds.Add(new WhereConditional(key, OpEnum.Eq, value));
            else
                conds.Add(new WhereConditional(key, OpEnum.IsNull, null));
            return this;
        }
        public CondCollection IsNull(string key)
        {
            conds.Add(new WhereConditional(key, OpEnum.IsNull, null));
            return this;
        }
        public CondCollection IsNotNull(string key)
        {
            conds.Add(new WhereConditional(key, OpEnum.IsNotNull, null));
            return this;
        }
        public CondCollection In(string key, params string[] value)
        {
            if (value != null && value.Count() > 0)
                conds.Add(new WhereConditional(key, OpEnum.In, value));
            else
                conds.Add(new WhereConditional(key, OpEnum.AwayFalse, value));
            return this;
        }
        public CondCollection NotEq(string key, object value)
        {
            if (value != null)
                conds.Add(new WhereConditional(key, OpEnum.NotEq, value));
            else
                conds.Add(new WhereConditional(key, OpEnum.IsNotNull, null));
            return this;
        }
        public CondCollection Lk(string key, string value)
        {
            if (value != null)
                conds.Add(new WhereConditional(key, OpEnum.FullLk, value));
            return this;
        }
        public CondCollection NotIn(string key, params string[] value)
        {
            if (value != null && value.Count() > 0)
                conds.Add(new WhereConditional(key, OpEnum.NotIn, value));
            return this;
        }
    }
    public class WhereConditional
    {
        static int counter;
        public string? ParamName { get; private set; }
        public WhereConditional(string field, OpEnum op, object? value)
        {
            Field = field;
            Op = op;
            Value = value;
            if (Op != OpEnum.In && Op != OpEnum.NotIn && Op != OpEnum.IsNull && Op != OpEnum.IsNotNull &&
                !string.IsNullOrWhiteSpace(field))
                ParamName = "@" + field + counter++;
        }
        public WhereConditional(string field)
        {
            Field = field;
            if (Op != OpEnum.In && Op != OpEnum.NotIn && Op != OpEnum.IsNull && Op != OpEnum.IsNotNull &&
                !string.IsNullOrWhiteSpace(field))
                ParamName = "@" + field + counter++;
        }
        public string Field { get; set; }
        public OpEnum Op { get; set; }
        public object? Value { get; set; }
        public string ToSql()
        {
            switch (Op)
            {
                case OpEnum.Eq:
                    return $" AND {Field} = {ParamName} ";
                case OpEnum.NotEq:
                    return $" AND {Field} != {ParamName} ";
                case OpEnum.FullLk:
                    return $" AND {Field} LIKE  {ParamName} ";
                case OpEnum.NotLk:
                    return $" AND {Field} NOT LIKE {ParamName} ";
                case OpEnum.Gt:
                    return $" AND {Field} > {ParamName} ";
                case OpEnum.Lt:
                    return $" AND {Field} < {ParamName} ";
                case OpEnum.Ge:
                    return $" AND {Field} >= {ParamName} ";
                case OpEnum.Le:
                    return $" AND {Field} <= {ParamName} ";
                case OpEnum.AwayTrue:
                    return " AND 1=1 ";
                case OpEnum.AwayFalse:
                    return " AND 1=2 ";
                case OpEnum.IsNull:
                    return $" AND {Field} IS NULL ";
                case OpEnum.IsNotNull:
                    return $" AND {Field} IS NOT NULL ";
            }
            if (Op == OpEnum.In)
            {
                if (Value == null) return " AND 1=2 ";
                if (Value.GetType().IsAssignableTo(typeof(IEnumerable<object>)))
                {
                    string s = "";
                    var valueAsArr = Value as IEnumerable<object>;
                    foreach (var v in valueAsArr!)
                    {
                        s += $"'{DataAccessUtils.Fix4SafeSql(v)}',";
                    }
                    if (s.Length > 0)
                        s = s.Substring(0, s.Length - 1);
                    return $" AND {Field} IN ({s}) ";
                }
            }
            else if (Op == OpEnum.NotIn)
            {
                if (Value == null) return " AND 1=2 ";
                if (Value.GetType().IsAssignableTo(typeof(IEnumerable<object>)))
                {
                    string s = "";
                    var valueAsArr = Value as IEnumerable<object>;
                    foreach (var v in valueAsArr!)
                    {
                        var ps = DataAccessUtils.Fix4SafeSql(v);
                        if (!String.IsNullOrWhiteSpace(ps)) s += $"'{ps}',";
                    }
                    if (s.Length > 0)
                        s = s.Substring(0, s.Length - 1);
                    if (s.Length > 0)
                    {
                        return $" AND {Field} NOT IN ({s}) ";
                    }
                    else
                    {
                        return " ";
                    }
                }
            }
            return " AND 1=2";
        }
    }
    public enum OpEnum
    {
        Eq, NotEq, FullLk, NotLk, In, Gt, Lt, Ge, Le, NotIn, IsNull, IsNotNull, AwayTrue, AwayFalse
    }
}